# 
LOCALIST_VERSION = '0.5'

class Localist

  # no default so internally usable as variables without the accessor
  class_attr_rw :callback, :strict2616
    
  class_attr_rw :auto_setup do 
    on_init do
      ENV["RAILS_ENV"].eql?('development') ? true : false 
    end
  end
  
  # no default so internally usable as variables without the accessor
  class_attr_rw :supported_locales do
    on_set do |input|
      # input needs to be passed to setup_assets() because @@supported_locales is not set yet
      setup_assets(input) if auto_setup
      input
    end
  end
  
  class_attr_rw :default_locale do 
    on_init do
      @@supported_locales.first
    end
    on_set do |input|
      supported?(input) or raise "The locale '#{input}' is not supported by the application."
      input
    end
  end
  
  class_attr_rw :symbol do
    on_init do
      :locale
    end
  end
  
  def self.country_code(locale)
    locale.split('-')[1]
  end
  
  def self.language_code(locale)
    locale.split('-')[0]
  end
  
  # is the locale supported?
  def self.supported?(locale)
    @@supported_locales.include?(locale)
  end
  
  def self.set(locale)
    if @@callback.nil?
      return
    elsif @@callback.is_a?(Proc)
      @@callback.call(locale)
    elsif @@callback.is_a?(Symbol)
      send(@@callback,locale)
    else
      raise "Wrong 'callback' type passed: #{Localist.callback.class}. It must be a Symbol or a Proc" 
    end
  end 
  
  def self.setup_assets(locales)
    flags_path = "#{RAILS_ROOT}/public/images/localist/flags"
    assets_path = "#{RAILS_ROOT}/vendor/plugins/localist/assets"
    assets_flag_path = "#{assets_path}/famfamfam_flag_icons/png"
    FileUtils.rm_rf(flags_path)
    FileUtils.makedirs(flags_path)
    flag_files = locales.map{|l| "#{assets_flag_path}/#{country_code(l).downcase}.png"}
    FileUtils.cp(flag_files, flags_path)
    FileUtils.cp("#{assets_path}/stylesheet.css", "#{RAILS_ROOT}/public/stylesheets/localist/stylesheet.css" )
  end
  
  # Matching rules defined in RFC 2616, 
  # section 14.4: HTTP/1.1 - Header Field Definitions - Accept-Language
  # returns the best language match or nil
  def self.best_match(client_str) # something like "it-IT;q=0.3, en-EN;q=0.5, *"
    client_str = client_str.dup
    client_locales = []
    client_accepts_any = false
    client_str.tr_s!(' ', '')
    client_str.downcase! # case insensitive match
    client_str.split(/,/).each do |tag|
      lan, q = tag.split(/;/)
      q = q.nil? ? 1 : q.sub(/q=/,'').to_f 
      if lan.eql?('*')
        client_accepts_any = true
      else
        client_locales << [ q, lan ]
      end
    end
    client_locales.sort!{|a,b| b[0] <=> a[0]}.map!{|a| a[1]}
    client_locales.each do |client_loc|
      @@supported_locales.each do |supported_loc|                        # client -> supported
        return supported_loc if client_loc.match(/^#{supported_loc}$/i) || # en-gb  -> en-gb
                                 supported_loc.match(/^#{client_loc}-/i) || # en     -> en-gb
                                 client_loc.match(/^#{supported_loc}-/i)    # en-gb  -> en
        unless @@strict2616
          match_obj = supported_loc.match(/^([^-]+)-/i)
          unless match_obj.nil?
            supp_l = match_obj.captures
            return supported_loc if client_loc.match(/^#{supp_l}-/i)       # en-us -> en-gb
          end
        end   
      end
    end
    client_accepts_any ? default_locale : nil
  end  
  
end 
